import os
import sys
import subprocess
import time
import resource
from pathlib import Path
from collections import defaultdict

def compile_cpp_files():
    """使用g++编译当前目录下所有的.cpp文件"""
    cpp_files = [f for f in os.listdir() if f.endswith('.cpp')]
    
    if not cpp_files:
        print("没有找到任何.cpp文件")
        return
    
    for cpp_file in cpp_files:
        output_name = Path(cpp_file).stem
        cmd = [
            'g++',
            '-std=c++11',
            cpp_file,
            '-o',
            output_name
        ]
        
        print(f"正在编译 {cpp_file}...")
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        if result.returncode != 0:
            print(f"编译 {cpp_file} 失败:")
            print(result.stderr)
        else:
            print(f"成功编译 {cpp_file} 为 {output_name}")

def process_test_file(cpp_path, test_file, output_file):
    """处理单个test.in文件，输出追加到指定文件"""
    subdir_name = test_file.parent.name
    
    with open(test_file, 'rb') as f:
        input_data = f.read()
    
    # 执行程序并捕获输出
    result = subprocess.run(
        [str(cpp_path), subdir_name],
        input=input_data,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE
    )
    
    # 追加写入输出文件
    with open(output_file, 'ab') as f:  # 使用追加二进制模式
        # 写入分隔线和测试文件名
        f.write(f"\n\n=== 测试文件: {test_file} ===\n".encode('utf-8'))
        # 写入程序输出
        f.write(result.stdout)
        # 如果有错误也写入
        if result.stderr:
            f.write(b"\n[ERROR]\n")
            f.write(result.stderr)
    
    if result.returncode != 0:
        print(f"执行 {cpp_path} 失败:")
        print(result.stderr.decode('utf-8'))

def traverse_directory(cpp_path, root_dir, output_file):
    """递归处理目录并将所有输出写入同一个文件"""
    root_path = Path(root_dir)
    
    # 清空或创建输出文件
    with open(output_file, 'wb') as f:
        pass
    
    for dirpath, _, filenames in os.walk(root_path):
        if 'test.in' in filenames:
            test_file = Path(dirpath) / 'test.in'
            process_test_file(cpp_path, test_file, output_file)
    print(f"已生成结果到 {output_file}")

def parse_key_value_file(filepath):
    """解析key,value格式的文件"""
    with open(filepath, 'r', encoding='utf-8') as f:
        return dict(line.strip().split(',', 1) for line in f if line.strip())

def run_accuracy_test(output_file, result_file):
    """运行准确率测试并生成汇总结果"""
    reference_file = Path("../data_converted/optima/optima.txt")
    
    if not reference_file.exists():
        print("错误: 参考文件不存在!")
        return
    
    # 收集所有测试结果
    test_results = []
    total_same = 0
    total_diff = 0
    total_dirty = 0
    
    # 解析输出文件中的结果
    with open(output_file, 'r', encoding='utf-8') as f:
        content = f.read()
    
    # 分割各个测试结果
    test_sections = content.split('=== 测试文件: ')[1:]
    
    for section in test_sections:
        # 提取文件名和内容
        filename, data = section.split(' ===\n', 1)
        filename = filename.strip()
        dataset_name = Path(filename).parent.name  # 提取数据集名称
        
        # 解析为字典
        output_data = {}
        for line in data.splitlines():
            if line.strip() and ',' in line:
                key, value = line.strip().split(',', 1)
                output_data[key] = value
        
        # 与参考文件比较
        file1_data = parse_key_value_file(reference_file)
        
        same = diff = dirty = 0
        if dataset_name in file1_data and dataset_name in output_data:
            val1 = file1_data[dataset_name]
            val2 = output_data[dataset_name]
            
            if val1 == '-2' or val2 == '-2':
                dirty += 1
            elif val1 == val2:
                same += 1
            else:
                diff += 1
        
        test_results.append({
            'filename': filename,
            'dataset': dataset_name,
            'same': same,
            'diff': diff,
            'dirty': dirty
        })
        
        total_same += same
        total_diff += diff
        total_dirty += dirty
    
    # 写入汇总结果
    with open(result_file, 'w', encoding='utf-8') as f:
        f.write("=== 测试结果汇总 ===\n")
        f.write(f"总测试文件数: {len(test_results)}\n")
        f.write(f"总有效数据: {total_diff + total_same}\n")
        f.write(f"总相同数: {total_same}\n")
        f.write(f"总不同数: {total_diff}\n")
        if(total_same + total_diff == 0):
            f.write(f"无有效数据\n")
        else:
            f.write(f"平均准确率: {total_same / (total_same + total_diff) * 100:.2f}%\n")
    
    print(f"已生成结果到 {result_file}")

def run_performance_test(algorithm, cpp_executable, data_dir, output_file):
    """运行性能测试并记录时间和内存使用"""
    performance_file = Path(f"../experiments/{algorithm}_01knapsack-01-performance-fixed.txt")
    
    # 记录开始时间和内存
    start_time = time.time()
    start_mem = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
    
    # 执行测试
    traverse_directory(cpp_executable, data_dir, output_file)
    
    # 记录结束时间和内存
    end_time = time.time()
    end_mem = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
    
    # 计算耗时和内存增量
    elapsed_time = end_time - start_time
    mem_used = (end_mem - start_mem) / 1024  # 转换为KB
    
    # 写入性能结果
    with open(performance_file, 'w', encoding='utf-8') as f:
        f.write("=== 性能测试结果 ===\n")
        f.write(f"算法: {algorithm}\n")
        f.write(f"总耗时: {elapsed_time:.4f} 秒\n")
        f.write(f"内存占用: {mem_used:.2f} KB\n")
        f.write(f"峰值内存: {end_mem / 1024:.2f} KB\n")
    
    print(f"已生成性能测试结果到 {performance_file}")

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("请指定算法名称作为参数 (例如: greedy)")
        sys.exit(1)

    algorithm = sys.argv[1]
    
    # 确保experiments目录存在
    experiments_dir = Path("../experiments")
    experiments_dir.mkdir(parents=True, exist_ok=True)
    
    # 1. 编译C++文件
    compile_cpp_files()
    
    # 2. 配置路径 - 使用修复后的数据集
    CPP_EXECUTABLE = Path(f"./{algorithm}_01knapsack").absolute()
    DATA_DIR = Path("../data_converted").absolute()  # 使用修复后的数据集
    OUTPUT_FILE = Path(f"../experiments/{algorithm}_01knapsack-01-fixed.txt")
    RESULT_FILE = Path(f"../experiments/{algorithm}_01knapsack-01-accuracy-fixed.txt")
    
    # 3. 验证路径
    if not CPP_EXECUTABLE.exists():
        print("错误: C++程序不存在!")
        sys.exit(1)
    if not DATA_DIR.exists():
        print("错误: 数据目录不存在!")
        sys.exit(1)
    
    # 4. 运行性能测试（包含时间和内存测量）
    run_performance_test(algorithm, CPP_EXECUTABLE, DATA_DIR, OUTPUT_FILE)
    
    # 5. 运行准确率测试
    run_accuracy_test(OUTPUT_FILE, RESULT_FILE) 